﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.Concurrent;
using System.Reflection;

namespace Framework.Reflection
{
    public static class DynamicsCache
    {
        static ConcurrentDictionary<Type, List<PropertyAccessor>> accessors = new ConcurrentDictionary<Type, List<PropertyAccessor>>();

        static object locker = new object();
        public class PropertyAccessor
        {
            public string PropertyName { get; set; }
            public PropertyGetterDelegate Getter { get; set; }
            public PropertySetterDelegate Setter { get; set; }
        }

        public static IEnumerable<PropertyAccessor> GetAccessors<T>()
        {
            return GetAccessors(typeof(T));
        }

        public static IEnumerable<PropertyAccessor> GetAccessors(Type type)
        {
            return accessors.GetOrAdd(type, (newKey) => builder(type));
        }

        static Func<Type, List<PropertyAccessor>> builder = (t) =>
        {
            var props = t.GetProperties(BindingFlags.Instance | BindingFlags.Public).Where(x => x.CanWrite);
            return  props.Select(x => new PropertyAccessor { 
                PropertyName = x.Name, 
                Getter = DynamicReflectionHelper.CreatePropertyGetter(x), 
                Setter = DynamicReflectionHelper.CreatePropertySetter(x) })
                .ToList();
        };
    }
}
